#pragma once

#include <boost/detail/workaround.hpp>

# pragma warning(push)
# pragma warning(disable:4996)
# pragma warning(disable:4510)
# pragma warning(disable:4610)

#include <cstddef>
#include <stdexcept>
#include <algorithm>
#include <string>
#include <sstream>
#include <boost/assert.hpp>
#include <boost/swap.hpp>
#include <boost/detail/iterator.hpp>
#include <boost/throw_exception.hpp>
#include <boost/config.hpp>

template<class T, std::size_t LEN = 0>
class Array {
private:
	T* elems;
	std::size_t N;
	std::size_t capality;
public:
	// type definitions
	typedef T value_type;
	typedef T* iterator;
	typedef const T* const_iterator;
	typedef T& reference;
	typedef const T& const_reference;
	typedef std::size_t size_type;
	typedef std::ptrdiff_t difference_type;

	Array() :
			elems(0), N(0), capality(0) {
		resize(LEN, value_type());
	}

	Array(std::size_t len, const value_type& val = value_type()) :
			elems(0), N(0), capality(0) {
		resize(len, val);
	}
	template<std::size_t LEN2>
	Array(const Array<T, LEN2>& other) :
			elems(0), N(0), capality(0) {
		resize(other.size());
		std::copy(other.begin(), other.end(), begin());
	}
	virtual ~Array() {
		if (elems) {
			delete[] elems;
		}
	}
	// check range (may be private because it is )
	void rangecheck(int i)const {
		if (i >= size()) {
			std::out_of_range e("Array<>: index out of range");
			boost::throw_exception(e);
		}
	}
	bool IncCapality(std::size_t newCapality, const value_type& val = value_type()) {
		if (newCapality <= capality) {
			return true;
		}
		T* p = new T[newCapality];
		if (!p) {
#ifdef _DEBUG
			throw exception("Alloc Memory Failed!");
#endif
			return false;
		}
		std::copy(begin(), end(), p);
		std::fill(p + N, p + newCapality, val);
		capality = newCapality;
		if (elems) {
			delete[] elems;
		}
		elems = p;
		return true;
	}
	bool resize(std::size_t newLen, const value_type& val = value_type()) {
		if (!IncCapality(newLen, val)) {
			return false;
		}
		N = newLen;
		return true;
	}
	// iterator support
	iterator begin() {
		if (!N) {
			return iterator(reinterpret_cast<T *>(this));
		}
		return elems;
	}
	const_iterator begin() const {
		if (!N) {
			return const_iterator(reinterpret_cast<const T *>(this));
		}
		return elems;
	}
	iterator end() {
		if (!N) {
			return begin();
		}
		return elems + N;
	}
	const_iterator end() const {
		if (!N) {
			return begin();
		}
		return elems + N;
	}

	// reverse iterator support
#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) && !defined(BOOST_MSVC_STD_ITERATOR) && !defined(BOOST_NO_STD_ITERATOR_TRAITS)
	typedef std::reverse_iterator<iterator> reverse_iterator;
	typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
#elif defined(_MSC_VER) && (_MSC_VER == 1300) && defined(BOOST_DINKUMWARE_STDLIB) && (BOOST_DINKUMWARE_STDLIB == 310)
	// workaround for broken reverse_iterator in VC7
	typedef std::reverse_iterator<std::_Ptrit<value_type, difference_type, iterator,
	reference, iterator, reference> > reverse_iterator;
	typedef std::reverse_iterator<std::_Ptrit<value_type, difference_type, const_iterator,
	const_reference, iterator, reference> > const_reverse_iterator;
#elif defined(_RWSTD_NO_CLASS_PARTIAL_SPEC)
	typedef std::reverse_iterator<iterator, std::random_access_iterator_tag,
	value_type, reference, iterator, difference_type> reverse_iterator;
	typedef std::reverse_iterator<const_iterator, std::random_access_iterator_tag,
	value_type, const_reference, const_iterator, difference_type> const_reverse_iterator;
#else
	// workaround for broken reverse_iterator implementations
	typedef std::reverse_iterator<iterator,T> reverse_iterator;
	typedef std::reverse_iterator<const_iterator,T> const_reverse_iterator;
#endif

	reverse_iterator rbegin() {
		return reverse_iterator(end());
	}
	const_reverse_iterator rbegin() const {
		return const_reverse_iterator(end());
	}
	reverse_iterator rend() {
		return reverse_iterator(begin());
	}
	const_reverse_iterator rend() const {
		return const_reverse_iterator(begin());
	}

	// operator[]
	reference operator[](size_type i) {
		BOOST_ASSERT( i < N && "out of range");
		return elems[i];
	}

	const_reference operator[](size_type i) const {
		BOOST_ASSERT( i < N && "out of range");
		return elems[i];
	}

	// at() with range check
	reference at(int i) {
		rangecheck(i);
		return elems[i];
	}
	const_reference at(int i) const {
		rangecheck(i);
		return elems[i];
	}

	// front() and back()
	reference front() {
		rangecheck(0);
		return elems[0];
	}

	const_reference front() const {
		rangecheck(0);
		return elems[0];
	}

	reference back() {
		rangecheck(N - 1); //if N==0, N-1 ==> FFFFFFFF, rangecheck failed!
		return elems[N - 1];
	}

	const_reference back() const {
		rangecheck(N - 1);
		return elems[N - 1];
	}

	// size is constant
	size_type size() const{
		return N;
	}
	size_type length() {
		return size();
	}
	bool empty() {
		return 0 == N;
	}
	size_type max_size() {
		return N;
	}

	// swap (note: linear complexity)
	template<std::size_t LEN2>
	void swap(Array<T, LEN2>& y) {
		assert(N == y.N);
		for (size_type i = 0; i < N; ++i)
			boost::swap(elems[i], y.elems[i]);
	}

	// direct access to data (read-only)
	const T* data() const {
		return elems;
	}
	T* data() {
		return elems;
	}

	// use Array as C Array (direct read/write access to data)
	T* c_array() {
		return elems;
	}

	// assignment with type conversion
	template<typename T2, std::size_t LEN2>
	Array<T, LEN>& operator=(Array<T2, LEN2>& rhs) {
		resize(rhs.size());
		std::copy(rhs.begin(), rhs.end(), begin());
		return *this;
	}
	template<typename T2, std::size_t LEN2>
	Array<T, LEN>& eat(Array<T2, LEN2>& rhs) {
		if (elems) {
			delete[] elems;
		}
		elems = rhs.elems;
		N = rhs.N;
		capality = rhs.capality;
		rhs.elems = 0;
		rhs.N = 0;
		rhs.capality = 0;
		return *this;
	}

	// assign one value to all elements
	void assign(const T& value) {
		fill(value);    // A synonym for fill
	}
	void fill(const T& value) {
		std::fill_n(begin(), size(), value);
	}

};

// comparisons
template<typename T, std::size_t LEN1, std::size_t LEN2>
bool operator==(const Array<T, LEN1>& x, const Array<T, LEN2>& y) {
	return (x.N == y.N) && std::equal(x.begin(), x.end(), y.begin());
}
template<class T, std::size_t LEN1, std::size_t LEN2>
bool operator<(const Array<T, LEN1>& x, const Array<T, LEN2>& y) {
	return std::lexicographical_compare(x.begin(), x.end(), y.begin(), y.end());
}
template<class T, std::size_t LEN1, std::size_t LEN2>
bool operator!=(const Array<T, LEN1>& x, const Array<T, LEN2>& y) {
	return !(x == y);
}
template<class T, std::size_t LEN1, std::size_t LEN2>
bool operator>(const Array<T, LEN1>& x, const Array<T, LEN2>& y) {
	return y < x;
}
template<class T, std::size_t LEN1, std::size_t LEN2>
bool operator<=(const Array<T, LEN1>& x, const Array<T, LEN2>& y) {
	return !(y < x);
}
template<class T, std::size_t LEN1, std::size_t LEN2>
bool operator>=(const Array<T, LEN1>& x, const Array<T, LEN2>& y) {
	return !(x < y);
}

// global swap()
template<class T, std::size_t LEN1, std::size_t LEN2>
inline void swap(Array<T, LEN1>& x, Array<T, LEN2>& y) {
	x.swap(y);
}

# pragma warning(pop)

//for log
#ifdef __SIMPLE_LOG__
template<typename T, std::size_t LEN>
Logger& operator <<(Logger& slog, Array<T, LEN>& val) {
	slog<<"Array:[";
	Array<T, LEN>::const_iterator it;
	for(it = val.begin(); it != val.end(); ++it) {
		if(it != val.begin()) {
			slog<<", ";
		}
		slog<<(*it);
	}
	slog<<"] ";
	return slog;
}
template<typename T, std::size_t LEN>
Logger& operator << (Logger& slog, const Array<T, LEN>& val) {
	return operator <<(slog, const_cast<Array<T, LEN>&>(val));
}
#endif



template<typename T>
class Array2: Array<Array<T> > {
};

